正規表現入門

2026年2月18日 大幅書換

はじめに

「正規表現」で文字列を検索すると検索の幅が広がってすごく便利です。 正規表現で文字列を置換処理をすると、今まではひとつひとつ手作業でやっていたことが一瞬で終わってしまうこともあります。 ただ正規表現は一般的にはあまりなじみがな無いかもしれませんし、「普通の文字列検索・置換処理だけでも十分」と思われる方も多いかもしれません。

私は自作のテキストエディタを作るにあたって、正規表現検索・置換処理も自作してみました。 自作した理由は、自作しないと「正規表現」に関する部分は他のライブラリ頼りになってしまいます。 もし頼りにしているライブラリに不具合や、ましてや開発が止まったり終わったりしてしまったりするともう対応できなくなってしまいます。 そんな訳で自作したのですが、結果的には自分も正規表現に沢山触れることになりまして、より理解が深まりました。

それとちょっとした心残りも書いておきます。 それは「戻り読み」機能と「先読み」機能についてなのですが、 これらの機能に「繰り返し」機能を含められればもっと使い勝手が良くなったはずなのですが、 残念ながら「再起呼び出し」を出来るような構造にしなかったために実装することができず、断念しました。 再起呼び出しが出来るようにしてあれば・・・実装することは可能だったのですが・・・、 作り始めた当初はこんな機能があるとは考えていませんでしたので・・・仕方ない・・・と諦めるしかありませんでした。


以下、その正規表現について自作したテキストエディタに実装した範囲内で解説したいと思います。



正規表現一覧

(1).(ピリオド)
(2)*
(3)+
(4)(pattern)
(5)(?:pattern)
(6)x|y
(7){min,max}
(8)[xyz]
(9)^, $
(10)\d
(11)\s
(12)(?<=pattern)
(13)(?<!pattern)
(14)(?=pattern)
(15)(?!pattern)
(16)??, *?, *+, {min,max}?
(17)\1~\9
(18)\


※TEditorMXには一部、独自仕様があります(改行コードは常に \r\n など)。詳しくはTEditorMX付属のヘルプをご覧下さい。







(1).(ピリオド)

.(ピリオド)は改行コード以外の1文字とマッチします。


<< では実際にやって確認しましょう >>

サンプルプログラム(sample1.cpp)をTeditorMXで開いて下画像のようにツールバーの検索文字列に
.(ピリオド)1文字を入力し、正規チェックボックスにチェックを入れ、 編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)※1を実行してみて下さい。

※1
(Ctrl+Down)とはCtrlキーとキャレットキーの下(Down)を同時に押すことです。 この場合Ctrlキーとキャレットキーの下(Down)を同時に押すことで下方向に検索処理が実行されます。 その都度ポップアップメニューを開いて項目を選択しなくても簡単に検索処理を実行することができます。


regexp_period.jpg

実行するたびに1文字毎にマッチ(選択範囲が移動)していきます。 ただし、改行コードとはマッチしませんので改行コードの手前まで来たら次の行へ移動します。


もし、「良く分からない」という場合にはポップアップメニューの【置換】(Ctrl+Shift+R)で文字列置換ダイアログを開いて検索文字列に同様の設定をし、 置換文字列に適当な文字(ここではイコール = )を指定し、置換を実行してみて下さい。 改行コード以外の文字がすべてイコール(=)に置換されるのが確認できると思います。

置換ダイアログ設定
regexp_period_okikae.jpg


置換前(test_period.txt)

a
bc
def
あいうえお


置換後

=
==
===
=====



置換文字列(=)の数を数えれば半角文字(アルファベット)と全角文字(ひらがな)に関係なく、各文字一つ一つと .(ピリオド)がマッチしていることが確認できると思います。


ページのTOPへ



(2)*

前のパターンの0回以上の繰り返しにマッチします。0回以上なので空文字列ともマッチします。 空文字列とは各文字の左側※2にあると仮定している文字数0の実体のない文字列のことです。 「空文字列とマッチ」と表現されているときは文字の左側にあると仮定している文字数0の実体のない文字列とマッチしているということです。

※2
正確には文字の周りのあらゆるところにあるとされていますが処理の都合上、文字の左側にのみあるものと仮定しています。



<< では実際にやって確認しましょう >>

サンプルプログラム(sample1.cpp)をTEditorMXで開いて下画像のようにツールバーの検索文字列に
.* と入力し、正規チェックボックスにチェックを入れ、 編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)を実行してみて下さい。

regexp_aster.jpg

実行するたびにキャレット以降の文字列または行頭以降の文字列(改行コードは含まれません)と改行コードの手前の空文字列とが交互にマッチするのが確認できると思います (空文字列は実体がないので選択状態にはなりませんがキャレットがその位置で止まります)。 これは . が改行コード以外の文字とマッチ※3し、* はそれの0回以上の繰り返しで更に最長マッチ※4というルールがあるため改行コードを含まない行全体が選択状態になります。 また、その後に続けて実行すると選択されていた文字列と改行コードの間にある空文字列とマッチするためそこでキャレットが止まります。 以降、それの繰り返しになります。

※3
本来の正規表現だと改行コードにもマッチするのが本来です。 ただしそれだと処理の都合上、不具合がでてしまいます(処理時間とかメモリ容量とか)。 なので、TEditorMXでは「改行コードとはマッチしない」という独自仕様になっています・・・が、 一般的にも「そう」しているだろうと思います。
※4
最長マッチは「マッチする文字列の中で一番長い文字列とマッチする」というルールです。 最長マッチというルールがあるおかげで常に同じ検索結果が得られるようになっています。




ページのTOPへ



(3)+

前のパターンの1回以上の繰り返しにマッチします。1回以上なので空文字列とはマッチしません。


<< では実際にやって確認しましょう >>

サンプルプログラム(sample1.cpp)をTEditorMXで開いて下画像のようにツールバーの検索文字列に
.+ と入力し、正規チェックボックスにチェックを入れ、 編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)を実行してみて下さい。

regexp_plus.jpg

実行するたびにキャレット以降の文字列または行全体(改行コードは含まれません)とマッチするのが確認できると思います。 これは . が改行コード以外の文字とマッチ※3し、 + はそれの1回以上の繰り返しで更に最長マッチ※4 というルールがあるため改行コードを含まない行全体が選択状態になります。 また + は1回以上なので改行コードしか含まれない行はパスされます(マッチしません)。 以降、実行するとこれらの繰り返しになります。


ページのTOPへ



(4)(pattern)

グルーピング。patternをひとまとまりの正規表現とします。 例えば (abc)+ とした場合には、1個以上の abc とマッチしますので、

abc
abcabc
abcabcabc

の何れにもマッチします。

また、優先順位を替えるためにも使用できます。

東京ドーム
東京タワー
東京駅
東京スカイツリー
東京都

の中から「東京スカイツリー」と「東京駅」を検索したい場合を考えます。

東京スカイツリー|駅

と記述してしまうと「東京スカイツリー」と「駅」にマッチして上手く検索できません。
そこでグルーピングを用いて、

東京(スカイツリー|駅)

と記述すると今度は「東京スカイツリー」と「東京駅」の両方を上手く検索することができます。
※『スカイツリー』と『駅』の間にある | は OR でこの後の方に出てきます。


この正規表現は、グルーピングとしての機能のほかに後方参照データを取得する目的でも使用されます。 詳しくは後方参照をご覧下さい。


ページのTOPへ



(5)(?:pattern)

グルーピング(キャプチャ無し)。使い方は普通のグルーピングと同じですがキャプチャ無しです。 「キャプチャ無し」とは後方参照(\1~\9)に対応する文字列を保持しないということです。 つまり後方参照(\1~\9)にマッチ文字列は割り当てられません。


ページのTOPへ



(6)x|y

正規表現 x または y にマッチします(OR)。


<< では実際にやって確認しましょう >>

サンプルプログラム(sample1.cpp)をTeditorMXで開き、ポップアップメニューの【検索】を選択して文字列検索ダイアログを表示させます。 続いて下画像のように検索文字列に unsigned (char|short) と入力 し、正規表現チェックボックスにチェックを入れて下さい。

regexp_or1.jpg


入力し終わったら検索開始ボタンを押して検索を実行してみて下さい。 正しく入力されていれば情報ウィンドウの検索結果タブに下画像のような結果が表示されると思います。

regexp_or2.jpg

マッチした行(3行)が表示されます。 74行と90行は unsigned char にマッチし、95行は unsigned short にマッチしました。 ORになっていますね。


ページのTOPへ



(7){min,max}

直前の正規表現の指定回数(min以上、max以下)の繰り返しにマッチします。 minとmaxは入れ替えても動作します。 {number} と指定するとnumber回ちょうどの繰り返しとマッチします。



<< では実際にやって確認しましょう >>

テキストファイル(repeat.txt)をTEditorMXで開き、ポップアップメニューの【検索】を選択して文字列検索ダイアログを表示させます。 続いて下画像のように検索文字列に (abc){2,3} と入力し、正規表現チェックボックスにチェックを入れて下さい。

regexp_repeat1.jpg


入力し終わったら検索開始ボタンを押して検索を実行してみて下さい。 正しく入力されていれば情報ウィンドウの検索結果タブに下画像のような結果が表示されると思います。

regexp_repeat2.jpg

マッチした行が3行表示されます。 え?2行じゃないの?と思われたかもしれませんが3行で良いのです。 2行、3行は{2,3}の範囲内なのでマッチして当然ですが、4行も行頭から3回目の繰り返しまでマッチします。 試しに4行をダブルクリックしてタグジャンプしてみて下さい。 マッチした文字列(選択されている文字列)は先頭から3回目までの繰り返しまでになっているのが確認できると思います(下画像)。

regexp_repeat3.jpg


『え~、4回の繰り返しなんだからマッチさせないでよ~』と思われた方、これは仕様なのでご容赦下さい。 もし4回以上の繰り返しとマッチさせたくないときには ver1.41で設けた新機能:否定の先読みをご利用ください。 書き方だけ示しておきますと (abc){2,3}(?!abc) と記述することで4回目以降の繰り返しがあった場合にはマッチしないようになります。 ...でもこれ、あまり意味がないかもしれません。やってみると分かりますが一番最後の3回繰り返しの部分が必ずマッチするからです。


ページのTOPへ



(8)[xyz]

キャラクタリスト。指定されたxyzの中の何れかにマッチします。 ハイフン(-)で範囲指定することも可能です。[0-9]と記述すると数字1文字にマッチしますし、 [A-Za-z]と記述しますとアルファベットの1文字とマッチします。 2バイト文字にも対応しています。 [あ-お]と記述しますとひらがなの「あぃいぅうぇえぉお」の中のいずれか1文字とマッチします。 文字コードはASCIIコード(半角文字)とシフトJISコード(全角文字)を用いることができます。文字コードはWindows付属のIME等で確認できますのでご覧下さい。


否定
キャラクタリストの先頭に ^ を置くと否定になります。 例えば[^0-9]と記述しますと数字以外の文字とマッチしますし、[^A-Za-z]と記述しますとアルファベット以外の文字とマッチします。

もし「改行コード」を指定したいという場合には必ず \r\n を指定して下さい。 これはTEditorMXの独自仕様で、本エディタの内部で改行コードは \r\nに置き換わっています。 「ファイル」として出力するときに、他の改行コードに改めて変換して出力しています。 また本エディタの内部で改行コード \r\n は、2バイト文字コード(シフトJISコード)と同等の扱いになっています。



<< では実際にやって確認しましょう >>

テキストファイル(charlist.txt)をTeditorMXで開いて下画像のようにツールバーの検索文字列に
[0-9] と入力し、正規チェックボックスにチェックを入れ、 編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)を実行してみて下さい。

regexp_charlist.jpg

実行するたびに数字1文字が次々とマッチ(選択範囲が移動)していきます。 [A-Z]、[ぁ-ん]、などいろいろ試してみて下さいね。

ひとつ書き忘れました。上の例(画像)では区別チェックボックスにチェックを入れていませんのでアルファベットの大文字・小文字は区別しません。 区別したいときには区別チェックボックスにチェックを入れて下さいね。


ページのTOPへ



(9)^, $

^ は行頭にマッチします。
$ は改行コードの直前、改行コードが無いときは行末にマッチします。


<< では実際にやって確認しましょう >>

テキストファイル(sample1.cpp)をTeditorMXで開いて下画像のようにツールバーの検索文字列に
^HANDLE と入力し、正規チェックボックスにチェックを入れ、 編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)を実行してみて下さい。

regexp_gyoutou_matu.jpg


行頭にある HANDLE という文字列にのみマッチするのが分かると思います。

また同様に検索文字列として ^$ と入力して同様に検索を実行してみて下さい。 ^$ は行頭と行末がくっついている状態・・・つまり改行コード以外何の文字も含まれない空行とマッチします。 何もない行とマッチしますのでキャレットが移動するだけになります。


ページのTOPへ



(10)\d

アラビア数字[0-9]1文字とマッチします。




ページのTOPへ



(11)\s

空白文字[ \f\n\r\t\v]とマッチします。




ページのTOPへ



(12)(?<=pattern)

肯定の戻り読み。patternが左側に存在するときマッチします。 戻り読みですのでマッチデータには含まれませんしキャプチャもされません。


<< では実際にやって確認しましょう >>

テキストファイル(lookreturn.txt)をTeditorMXで開いて下画像のようにツールバーの検索文字列に
(?<=sd)ram と入力し、正規チェックボックスにチェックを入れ、 編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)を実行してみて下さい。

regexp_returnposi.jpg


実行するとsdramのramにのみマッチします。




ページのTOPへ



(13)(?<!pattern)

否定の戻り読み。patternが左側に存在しないときマッチします。 戻り読みですのでマッチデータには含まれませんしキャプチャもされません。


<< では実際にやって確認しましょう >>

テキストファイル(lookreturn.txt)をTeditorMXで開いて下画像のようにツールバーの検索文字列に
(?<!sd)ram と入力し、正規チェックボックスにチェックを入れ、 編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)を実行してみて下さい。

regexp_returnnega.jpg


実行するとsdram以外のramにマッチします。




ページのTOPへ



(14)(?=pattern)

肯定の先読み。patternが右側に存在するときマッチします。 先読みですのでマッチデータには含まれませんしキャプチャもされません。


<< では実際にやって確認しましょう >>

テキストファイル(lookreturn.txt)をTeditorMXで開いて下画像のようにツールバーの検索文字列に
windows(?=\s10) と入力し、正規チェックボックスにチェックを入れ、 編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)を実行してみて下さい。

regexp_lookposi.jpg


実行するとwindows 10のwindowsにのみマッチします。




ページのTOPへ



(15)(?!pattern)

否定の先読み。patternが右側に存在しないときマッチします。 先読みですのでマッチデータには含まれませんしキャプチャもされません。


<< では実際にやって確認しましょう >>

テキストファイル(lookreturn.txt)をTeditorMXで開いて下画像のようにツールバーの検索文字列に
windows(?!\s10) と入力し、正規チェックボックスにチェックを入れ、 編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)を実行してみて下さい。

regexp_looknega.jpg


実行するとwindows 10以外のwindowsにマッチします。




ページのTOPへ



(16)??, *?, +?, {min,max}?

繰り返しの正規表現に続けて ? を記述すると最短マッチになります。 通常は『最長マッチ』です。『最長マッチ』とはマッチするデータの中で最長のものをマッチデータとすることです。 それに対して『最短マッチ』はマッチデータの中で最短となるものをマッチデータとします。

どのようなときに用いるのか...と言いますと例えば次のようなHTMLのタグを検索するときを考えます。

<a href="#..."> comment .... </a>

最初の <a href="#..."> を検索(マッチ)したい場合に <a\s.*> という正規表現で検索したとします。 すると最長マッチですので行末に記述されている終了タグの > までマッチしてしまいます。 これでは上手くありません。 このようなときに『最短マッチ』の出番です。 繰り返しの正規表現 * の後に ? を付けて <a\s.*?> とします。 これで検索を実行しますと上手く検索(マッチ)させることができます。



<< では実際にやって確認しましょう >>

テキストファイル(saitann.txt)をTeditorMXで開いて下画像のようにツールバーの検索文字列に
<a\s.*> と入力し、正規チェックボックスにチェックを入れ、 編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)を実行してみて下さい。

regexp_saitann1.jpg


実行すると最長マッチですので終了タグまで(行全体)がマッチしてしまいます。

<a href="#..."> comment .... </a>       ← 行全体がマッチしてしまう


続いて繰り返しの正規表現 *? を付けて <a\s.*?> と入力し、実行してみて下さい。

regexp_saitann2


今度は commentの前の > までがマッチして期待通りの動作をします。

<a href="#..."> comment .... </a>       ← 期待通りにマッチ




ページのTOPへ



(17)\1~\9

\1~\9は後方参照と呼ばれ、検索時にグルーピング (pattern) の中の正規表現とマッチした文字列に置き換えられます。 \1, \2等の番号は左側から順番に数えたときの出現位置になります。

(abc)de(fgh)ij(klm)(nopqr)


として検索したときに得られる後方参照は、
  \1 = abc
  \2 = fgh
  \3 = klm
  \4 = nopqr
となります。


また、グルーピング(キャプチャ無し)(?:pattern) を用いますとキャプチャされませんので次のようになります。

(abc)de(?:fgh)ij(?:klm)(nopqr)


として検索したときに得られる後方参照は、
  \1 = abc
  \2 = nopqr
となります。


その他、文字列置換時(置換文字列)にだけ用いることができる後方参照 \0 があります。 \0 は、マッチデータすべての文字列を表します。


余談ですが、私の場合、後方参照は文字列検索時よりも文字列置換時に用いることが多いです。 「ある文字列にこの文字列を追加したい」とか「ある文字列からこの文字列を削除したい」とかいうときがよくあります。 そのようなときに『文字列置換+後方参照』は強力な武器になってくれます。




ページのTOPへ



(18)\

メタ文字の持つ特別な意味を失わせます。



\. → ただの .(ピリオド)
\* → ただの *(アスタリスク)
\( → ただの前括弧 (
\) → ただの閉じ括弧 )




ページのTOPへ






メニュー